package com.sdry.untils;

import org.apache.poi.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * @author tdd
 * @version V1.0
 * @ClassName: WordUtil
 * @Description:
 * @date 2020/4/8 16:50
 */
public class WordUtil {
    /**
     * 判断文本中时候包含字符串
     * @param text 文本
     * @param s 字符串
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text,String s){
        boolean check  =  false;
        if(text.indexOf(s)!= -1){
            check = true;
        }
        return check;
    }
    /**
     * 根据模板生成新word文档
     * 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
     * @param inputUrl 模板存放地址
     * @param outputUrl 新文档存放地址
     * @param s 判断替换标识
     * @param textMap 需要替换的信息集合
     * @param tableAddMap 表格插入信息 需插入行标识（在空白行第一行，即表头下一行） 插入数据
     * @return 成功返回true,失败返回false
     */
    public static boolean changWord(String inputUrl, String outputUrl,String s,
                                    Map<String, String> textMap, Map<String, List<String[]>> tableAddMap) {

        //模板转换默认成功
        boolean changeFlag = true;
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
            //解析替换文本段落对象
            WordUtil.changeText(document, textMap,s);
            //解析替换表格对象
            WordUtil.changeTable(document, textMap, tableAddMap,s);


            //生成新的word
            File file = new File(outputUrl);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();

        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }

        return changeFlag;

    }

    /**
     * 替换段落文本
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     * @param s 判断替换标识
     */
    public static void changeText(XWPFDocument document, Map<String, String> textMap,String s){
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if(checkText(text,s)){
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    run.setText(changeValue(run.toString(), textMap,s),0);
                }
            }
        }

    }

    /**
     * 匹配传入信息集合与模板
     * @param value 模板需要替换的区域
     * @param textMap 传入信息集合
     * @param s 判断替换标识
     * @return 模板需要替换区域信息集合对应值
     */
    public static String changeValue(String value, Map<String, String> textMap,String s){
        Set<Map.Entry<String, String>> textSets = textMap.entrySet();
        for (Map.Entry<String, String> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = "${"+textSet.getKey()+"}";
            if(value.indexOf(key)!= -1){
                if(null != textSet.getValue()){
                    value = value.replace(key,textSet.getValue());
                }else{
                    value = value.replace(key,"");
                }

                //value = textSet.getValue();
            }
        }
        //模板未匹配到区域替换为空
        if(checkText(value,s)){
            value = "";
        }
        return value;
    }

    /**
     * 替换表格对象方法
     * @param document docx解析对象
     * @param textMap 需要替换的信息集合
     * @param tableAddMap 需要插入的表格信息集合
     * @param s 判断替换标识
     */
    public static void changeTable(XWPFDocument document, Map<String, String> textMap,
                                   Map<String, List<String[]>> tableAddMap,String s){
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();
        for (int i = 0; i < tables.size(); i++) {
            //只处理行数大于等于2的表格，且不循环表头
            XWPFTable table = tables.get(i);
            if(table.getRows().size()>1){
                List<XWPFTableRow> rows = table.getRows();
                //判断表格是否需要替换，判断逻辑有$为替换
                if(checkText(table.getText(),s)){
                    //遍历表格,并替换模板
                    eachTable(rows, textMap,s);
                }
                //判断表格是否需要插入，判断逻辑有<table>为插入 返回插入行
                Set<Map.Entry<String, List<String[]>>> textSets = tableAddMap.entrySet();
                for (Map.Entry<String, List<String[]>> textSet : textSets) {
                    //匹配模板与替换值 格式key
                    String key = textSet.getKey();
                    int rowLine = findRowLine(rows,key);
                    if(rowLine > -1){
                        insertTable(table, textSet.getValue(),rowLine);
                    }

                }
            }
        }
    }

    /**
     * 遍历表格
     * @param rows 表格行对象
     * @param s 判断替换标识
     */
    public static int findRowLine(List<XWPFTableRow> rows,String s){
        int rowLine = -1;
        loop:for(int i = 0; i < rows.size(); i++){
            XWPFTableRow row = rows.get(i);
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if(checkText(cell.getText(),s)){
                    rowLine = i;
                    break loop;
                }
            }

        }
        return rowLine;
    }


    /**
     * 遍历表格
     * @param rows 表格行对象
     * @param textMap 需要替换的信息集合
     * @param s 判断替换标识
     */
    public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap,String s){
        for (XWPFTableRow row : rows) {
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if(checkText(cell.getText(),s)){
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List<XWPFRun> runs = paragraph.getRuns();
                        for (XWPFRun run : runs) {
                            run.setText(changeValue(run.toString(), textMap,s),0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 为表格插入数据，行数不够添加新行
     * @param table 需要插入数据的表格
     * @param tableList 插入数据集合
     * @param rowLine 插入数据开始行
     */
    public static void insertTable(XWPFTable table, List<String[]> tableList,int rowLine){
        //获取需要复制的表格
        XWPFTableRow oldRow = table.getRow(rowLine);
        //删除段落
        oldRow.getTableCells().get(0).removeParagraph(0);
        //oldRow.getTableCells().get(0).getParagraphs().get(0).getRuns().get(0).setText("",0);
        for(int i = 0; i < tableList.size(); i++){
            if(i != 0){
                XWPFTableRow row = table.insertNewTableRow(rowLine+i);//添加一个新行
                copyTableRow(row,oldRow,rowLine+i,1);
            }
            XWPFTableRow newRow = table.getRow(rowLine+i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for(int j = 0; j < cells.size(); j++){
                XWPFTableCell cell = cells.get(j);
                cell.setText(tableList.get(i)[j]);
                /*List<XWPFParagraph> paragraphs = cell.getParagraphs();
                if(paragraphs.size() <= 0){
                    cell.addParagraph();
                    cell.getParagraphs().get(0).createRun();
                }
                List<XWPFRun> runs = cell.getParagraphs().get(0).getRuns();
                if(runs.size() <= 0){
                    cell.getParagraphs().get(0).createRun();
                }
                cell.getParagraphs().get(0).getRuns().get(0).setText(tableList.get(i)[j],0);*/

            }
        }
    }

    /**
     * 功能描述:复制行，从source到target
     *
     * @param target
     * @param source
     * @param index
     * @param type 判断是否需要复制内容 0是 1否
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static void copyTableRow(XWPFTableRow target, XWPFTableRow
            source, Integer index,int type) {
        // 复制样式
        if (source.getCtRow() != null) {
            target.getCtRow().setTrPr(source.getCtRow().getTrPr());
        }
        // 复制单元格
        for (int i = 0; i < source.getTableCells().size(); i++) {
            XWPFTableCell cell1 = target.getCell(i);
            XWPFTableCell cell2 = source.getCell(i);
            if (cell1 == null) {
                cell1 = target.addNewTableCell();
            }
            //功能描述:复制单元格，从source到target
            copyTableCell(cell1,cell2,index,type);
        }
    }

    /**
     * 功能描述:复制单元格，从source到target
     *
     * @param target
     * @param source
     * @param index
     * @param type 判断是否需要复制内容 0是 1否
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static void copyTableCell(XWPFTableCell target,
                                     XWPFTableCell source, Integer index,int type) {
        // 列属性
        if (source.getCTTc() != null) {
            target.getCTTc().setTcPr(source.getCTTc().getTcPr());
        }
        // 删除段落
        for (int pos = 0; pos < target.getParagraphs().size(); pos++) {
            target.removeParagraph(pos);
        }
        //判断是否需要复制内容 0是 1否
        if(type == 0){
            // 添加段落
            for (XWPFParagraph sp : source.getParagraphs()) {
                XWPFParagraph targetP = target.addParagraph();
                copyParagraph(targetP, sp, index);
            }
        }
    }
    /**
     * 功能描述:复制段落，从source到target
     *
     * @param target
     * @param source
     * @param index
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static void copyParagraph(XWPFParagraph target,
                                     XWPFParagraph source, Integer index) {
        // 设置段落样式
        target.getCTP().setPPr(source.getCTP().getPPr());
        // 移除所有的run
        for (int pos = target.getRuns().size() - 1; pos >= 0; pos--) {
            target.removeRun(pos);
        }
        // copy 新的run
        for (XWPFRun s : source.getRuns()) {
            XWPFRun targetrun = target.createRun();
            copyRun(targetrun, s, index);
        }
    }
    /**
     * 功能描述:复制RUN，从source到target
     *
     * @param target
     * @param source
     * @param index
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static void copyRun(XWPFRun target, XWPFRun source, Integer
            index) {
        // 设置run属性
        target.getCTR().setRPr(source.getCTR().getRPr());
        // 设置文本
        String tail = "";
        if (index != null) {
            tail = index.toString();
        }
        target.setText(source.text().replace("}", "") + tail + "}");
    }


    /*public static void main(String[] args) {
        //模板文件地址
        String inputUrl = "C:\\Users\\Administrator\\Desktop\\打印文件\\出库单.docx";
        //新生产的模板文件
        String outputUrl = "C:\\Users\\Administrator\\Desktop\\打印文件\\出1.docx";
        //判断替换标识
        String s = "$";
        //${}替换
        Map<String, String> testMap = new HashMap<String, String>();
        testMap.put("osoNumber", "123456789");
        testMap.put("createDate", "2020-4-8 14:57:42");
        testMap.put("createBy", "创建人");
        testMap.put("logisticsPersonnel", "人");
        testMap.put("godownKeeperUser", "库管");
        testMap.put("hqTestUser", "检验人");

        //表格插入信息 需插入行标识（在空白行第一行，即表头下一行） 插入数据
        Map<String, List<String[]>> tableAddMap = new HashMap<String, List<String[]>>();
        List<String[]> testList = new ArrayList<String[]>();
        testList.add(new String[]{"1","1-1","1-2","1-3","1-4","1-5","1-6","1-7"});
        testList.add(new String[]{"2","2-1","2-2","2-3","2-4","2-5","2-6","2-7"});
        tableAddMap.put("<table>",testList);

        WordUtil.changWord(inputUrl, outputUrl,s, testMap, tableAddMap);
    }*/
}
